from main.model.devices.cpu import CPU
from main.model.devices.device_manager import DeviceManager
from main.model.logic.software.instructions import Add, Compare, IOInstruction
from main.model.logic.usher import Usher
from main.model.devices.clock import Clock
from main.model.devices.disk import Disk
from main.model.logic.kernel import Kernel
from main.model.logic.software.program import Program
from main.model.logic.input_output import InOut
from main.model.logic.output import Output
from main.model.devices.memory.virtual_memory import VirtualMemory

class System(object):
    
    def __init__(self, delay=600, round_robin_enable=False, log=True):
        self.os_usher       = Usher()
        self.disk           = Disk()
        self.memory         = VirtualMemory()
        self.cpu            = CPU(self.os_usher)
        self.io             = InOut()
        self.clock          = Clock(delay)
        self.output         = Output(log)
        self.device_manager = DeviceManager(self.disk, self.memory, self.cpu, self.io, self.output)
        self.kernel         = Kernel(self.device_manager, self.os_usher, round_robin_enable)
        self.cpu.kernel     = self.kernel
        self.io.kernel      = self.kernel
        
        self.clock.add_listener(self.cpu)
        self.clock.add_listener(self.io)
        
        
    def with_programs(self, amount):
        for program_index in range (0, amount ):
            self.disk.save(Program("program a#" + str(program_index)).add(
                            Add([1, 1])).add(
                            Add([1, 2])).add(
                            Add([1, 2])).add(
                            Add([1, 2])).add(
                            Add([1, 3])).add(
                            IOInstruction([1, 4])).add(
                            Compare([1, 5])).add(
                            Compare([1, 6])))
    
            self.disk.save(Program("program b#" + str(program_index)).add(
                            Add([3, 2])).add(
                            Compare([5, 2])))
        return self
        
    def power_on(self):
        self.io.start()
        self.clock.start()
        self.kernel.start()
        return self
